using System;

namespace RapidHDL
{
	/// <summary>
	/// Summary description for Conversion.
	/// </summary>
	public class Conversion
	{
		public Conversion()
		{
			//
			// TODO: Add constructor logic here
			//
		}

		/*public static NodeVector BuildStateVector(string psStateString)
		{
			int iIndex;
			string sStateString = psStateString.ToUpper().Trim();
			char cValue;
			Node ndNode;

			NodeVector nvNodeVector = new NodeVector(sStateString.Length);
			for(iIndex = 0; iIndex < sStateString.Length; iIndex++)
			{
				ndNode = nvNodeVector[iIndex];
				cValue = sStateString[iIndex];
				switch(cValue)
				{
					case 'X' :
						ndNode.NodeState = NodeState.Undefined;
						break;
					case '1' :
						ndNode.NodeState = NodeState.High;
						break;
					case '0' :
						ndNode.NodeState = NodeState.Low;
						break;
					case 'Z' :
						ndNode.NodeState = NodeState.Tri;
						break;
					default:
						System.Diagnostics.Debug.Assert(false,"Bad State Vector");
						break;
				}
			}
			return nvNodeVector;
		}*/

        public static string UIntToBinaryString(uint piInputInt, int piLength)
        {
            string sBinary;

            uint iQ = piInputInt / 2;
            uint iR = piInputInt % 2;

            if (iR == 1)
                sBinary = "1";
            else
                sBinary = "0";

            while (iQ > 0)
            {
                iR = iQ % 2;
                iQ = iQ / 2;

                if (iR == 0)
                    sBinary = "0" + sBinary;
                else
                    sBinary = "1" + sBinary;
            }

            if (piLength != 0)
            {
                sBinary = sBinary.PadLeft(piLength, '0');
                return sBinary.Substring(sBinary.Length - piLength, piLength);
            }
            else
            {
                return sBinary;
            }
        }


		public static string IntToBinaryString(int piInputInt, int piLength)
		{
			string sBinary;

            if (piInputInt < 0)
                return UIntToBinaryString((uint)piInputInt, piLength);

			int iQ = piInputInt / 2;
			int iR = piInputInt % 2;
			
			if(iR == 1)
				sBinary = "1";
			else
				sBinary = "0";

			while(iQ > 0)
			{
				iR = iQ % 2;
				iQ = iQ / 2;
				
				if(iR == 0)
					sBinary = "0" + sBinary;
				else
					sBinary = "1" + sBinary;
			}

			if (piLength != 0)
			{
				sBinary = sBinary.PadLeft(piLength,'0');
				return sBinary.Substring(sBinary.Length - piLength,piLength);
			}
			else
			{
				return sBinary;
			}
		}

        public static string SelectBinarySubset(string psBinary, int piStartBit, int piEndBit, bool pbPadLeft)
        {
            string sResult;

            int iStart = piStartBit;
            int iEnd = piEndBit;
            if (iStart > iEnd)
            {
                iEnd = piStartBit;
                iStart = piEndBit;
            }

            int iLen = iEnd - iStart + 1;
            int iEndIdx = psBinary.Length - iStart;

            if (psBinary.Length == iLen && iEndIdx == 1)
                return psBinary;

            int iStartIdx = iEndIdx - iLen;
            
            if (iEndIdx < 1)
            {
                return "";
            }

            
            if (iStartIdx < 0)
            {
                sResult = psBinary.Substring(0,iLen + iStartIdx); 
                if (pbPadLeft)
                    sResult = sResult.PadLeft(iLen,'0');

            }
            else
            {
                sResult = psBinary.Substring(iStartIdx,iLen);
            }

            return sResult;
        }

        public static bool IsNumeric(string psTest)
        {
            double result;
            return (Double.TryParse(psTest,out result));
        }

        public static int MinBitWidth(int iSize)
        {
            string sValue = IntToBinaryString(iSize);
            return sValue.Length;
        }

        public static int StringToInt(string psValue)
        {
            int value;
            try
            {
                value = System.Convert.ToInt32(psValue.Trim());
            }
            catch
            {
                value = 0;
            }
            return value;
        }

        public static string ReverseString(string psValue)
        {
            char[] saArray = psValue.ToCharArray();
            Array.Reverse(saArray);
            return new string(saArray);
        }

        public static string CodeOneHot(int piValue, int piWidth)
        {
            if (piValue > piWidth - 1)
                return new String('0', piWidth);

            string sResult = new String('0', piWidth - 1);
            sResult = sResult.Insert(piWidth-piValue-1, "1");
            return sResult;
        }


        //-------------------

        public static string Left(string psInput, int piLen)
        {
            if (psInput.Length <= piLen)
                return psInput;

            return psInput.Substring(0, piLen);
        }

        public static string Right(string psInput, int piLen)
        {
            if (psInput.Length <= piLen)
                return psInput;

            return psInput.Substring(psInput.Length - piLen, piLen);
        }


        public static string StringBinaryToHex(string psInput)
        {
            string sHex = "";
            string sNibble = "";
            string sInput = psInput;

            do
            {
                sNibble = Right(sInput, 4);
                if (sInput.Length > 4)
                    sInput = Left(sInput, sInput.Length - 4);
                else
                    sInput = "";
                sHex = StringBinaryNibbleToHexChar(sNibble) + sHex;
            }
            while (sInput.Length > 0);

            return sHex;
        }

        public static string StringHexToBinary(string psInput)
        {
            string sBinary = "";
            string sNibble = "";
            string sInput = psInput;

            do
            {
                sNibble = Right(sInput, 1);
                if (sInput.Length > 1)
                    sInput = Left(sInput, sInput.Length - 1);
                else
                    sInput = "";
                sBinary = StringHexNibbleToBinary(sNibble) + sBinary;
            }
            while (sInput.Length > 0);

            return sBinary;
        }


        public static string StringBinaryNibbleToHexChar(string psBinary)
        {
            string sBinary = psBinary;
            if (sBinary.Length > 4)
                sBinary = Right(sBinary, 4);
            int iBin = StringBinaryToInt(sBinary);
            if (iBin < 10)
                return iBin.ToString();

            switch (iBin)
            {
                case 10:
                    return "A";
                case 11:
                    return "B";
                case 12:
                    return "C";
                case 13:
                    return "D";
                case 14:
                    return "E";
                case 15:
                    return "F";
            }
            return "X";
        }

        public static string StringHexNibbleToBinary(string psHex)
        {
            string sHex = Right(psHex, 1);

            switch (sHex)
            {
                case "0":
                    return "0000";
                case "1":
                    return "0001";
                case "2":
                    return "0010";
                case "3":
                    return "0011";
                case "4":
                    return "0100";
                case "5":
                    return "0101";
                case "6":
                    return "0110";
                case "7":
                    return "0111";
                case "8":
                    return "1000";
                case "9":
                    return "1001";
                case "A":
                    return "1010";
                case "B":
                    return "1011";
                case "C":
                    return "1100";
                case "D":
                    return "1101";
                case "E":
                    return "1110";
                case "F":
                    return "1111";
            }
            return "XXXX";
        }

        public static long StringBinaryToSignedLong(string psBinary)
        {
            if (Left(psBinary, 1) == "0")
                return StringBinaryToLong(psBinary);

            string sTwos = StringBinaryTwosComp(psBinary, psBinary.Length);
            return StringBinaryToLong(sTwos) * (-1);
        }

        public static string SignedLongToBinaryString(long plUnsigned, int piLength)
        {
            if (plUnsigned >= 0)
                return LongToBinaryString(plUnsigned, piLength);

            string sBinary = LongToBinaryString(plUnsigned * -1, piLength);
            return StringBinaryTwosComp(sBinary, piLength);
        }

        public static int StringBinaryToInt(string psBinary)
        {
            return (int)StringBinaryToLong(psBinary);
        }


        public static long StringBinaryToLong(string psBinary)
        {
            long iLength = psBinary.Length;
            long iResult = 0;

            for (long iIndex = 0; iIndex < iLength; iIndex++)
            {
                if (psBinary.Substring((int)(iLength - iIndex - 1), 1) == "1")
                    iResult += (long)System.Math.Pow(2.0, (double)iIndex);
                else
                {
                    if (psBinary.Substring((int)(iLength - iIndex - 1), 1) != "0")
                    {
                        return -377;
                    }
                }
            }
            return iResult;
        }

        public static long TwosComplementLong(long plInput, int piLength)
        {
            string sBinary = LongToBinaryString(plInput, piLength);
            sBinary = StringBinaryTwosComp(sBinary, piLength);
            return StringBinaryToLong(sBinary);
        }

        public static int TwosComplement(int piInput, int piLength)
        {
            string sBinary = IntToBinaryString(piInput, piLength);
            sBinary = StringBinaryTwosComp(sBinary, piLength);
            return StringBinaryToInt(sBinary);
        }

        public static string StringBinaryTwosComp(string psBinary, int piLength)
        {
            string sBinary = psBinary;
            string sTwos = "";
            int iLen = psBinary.Length;

            if (iLen < piLength)
            {
                sBinary = new string('0', piLength) + sBinary;
                sBinary = Right(sBinary, piLength);
            }

            for (int iIdx = 0; iIdx < iLen; iIdx++)
            {
                if (sBinary.Substring(iIdx, 1) == "1")
                    sTwos += "0";
                else
                    sTwos += "1";
            }

            long lConvert = StringBinaryToLong(sTwos);
            lConvert++;
            return LongToBinaryString(lConvert, piLength);
        }

        public static string LongToBinaryString(long plInputLong, int piLength)
        {
            string sBinary;

            long iQ = plInputLong / 2;
            long iR = plInputLong % 2;

            if (iR == 1)
                sBinary = "1";
            else
                sBinary = "0";

            while (iQ > 0)
            {
                iR = iQ % 2;
                iQ = iQ / 2;

                if (iR == 0)
                    sBinary = "0" + sBinary;
                else
                    sBinary = "1" + sBinary;
            }

            if (piLength != 0)
            {
                sBinary = sBinary.PadLeft(piLength, '0');
                return sBinary.Substring(sBinary.Length - piLength, piLength);
            }
            else
            {
                return sBinary;
            }
        }

        public static string IntToBinaryString(int piInputInt)
        {
            return IntToBinaryString(piInputInt, 0);
        }

        public static long StringBinaryToLong(string psBinary, int piLength)
        {
            long iLength = psBinary.Length;
            long iResult = 0;

            for (long iIndex = 0; iIndex < iLength; iIndex++)
            {
                if (psBinary.Substring((int)(iLength - iIndex - 1), 1) == "1")
                    iResult += (long)System.Math.Pow(2.0, (double)iIndex);
                else
                {
                    if (psBinary.Substring((int)(iLength - iIndex - 1), 1) != "0")
                    {
                        return -377;
                    }
                }
            }
            return iResult;
        }

        public static bool StringBinaryToBool(string psBinary)
        {
            string sTest = new String('0', psBinary.Length);
            if (sTest == psBinary)
                return false;
            else
                return true;
        }

        public static string StringBinaryFormat(string psBinary, string psFormatCode)
        {
            switch (Left(psFormatCode.ToUpper(), 1))
            {
                case "S":
                    return StringBinaryToSignedLong(psBinary).ToString();
                case "H":
                    return StringBinaryToHex(psBinary);
                case "B":
                    return StringBinaryToBool(psBinary).ToString();
                case "U":
                    return StringBinaryToLong(psBinary).ToString();
            }
            return psBinary;
        }

        public static long StringToLong(string psValue)
        {
            long value;
            try
            {
                value = System.Convert.ToInt64(psValue.Trim());
            }
            catch
            {
                value = 0;
            }
            return value;
        }

        public static void UIntToShorts(uint piIn, ref ushort psHigh, ref ushort psLow)
        {
            psHigh = (ushort)((piIn >> 16) & 0x0000FFFF);
            psLow = (ushort)((piIn & 0x0000FFFF));
        }

        public static uint ShortsToUInt(ushort psHigh, ushort psLow)
        {
            uint iResult = (uint)(psHigh << 16)  | (uint)psLow;
            return iResult;
        }

        public static bool IsAnyStringNumeric(string psValue)
        {
            try
            {
                int iTest = AnyStringToInt(psValue);
            }
            catch
            {
                return false;
            }
            return true;
        }

        public static int AnyStringToInt(string psValue)
        {
            string sValue = psValue.Trim().ToUpper();
            if (IsNumeric(psValue))
                return StringToInt(psValue);
            if (psValue.Length < 3)
                throw new Exception(psValue + " is not numeric.");

            string sLeft = psValue.Substring(0,2);
            string sRight = psValue.Substring(2,psValue.Length - 2);

            if (sLeft == "0X")
            {
                string sTest = sRight.Replace('A','1').Replace('B','1').Replace('C','1').Replace('D','1').Replace('E','1').Replace('F','1');
                if (!IsNumeric(sTest))
                    throw new Exception(psValue + " is not numeric.");
                return Conversion.StringBinaryToInt(Conversion.StringHexToBinary(sRight));
            }

            if (sLeft == "0B")
            {
                if (!IsNumeric(sRight))
                    throw new Exception(psValue + " is not numeric.");
                if (sRight.IndexOfAny(new char[] {'2','3','4','5','6','7','8','9'}) > -1)
                {
                    throw new Exception(psValue + " is not numeric.");
                }
                return Conversion.StringBinaryToInt(sRight);
            }
            throw new Exception(psValue + " is not numeric.");            
        }
    }
	
}
